package com.jiangruan.javaPro.address;

import com.jiangruan.javaPro.tools.Base58;
import com.jiangruan.javaPro.tools.Hash;
import sun.security.util.Length;

import java.security.*;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECPoint;
import java.util.Arrays;

/**
 * @author:冷风诉离歌
 * @desc:该类用于推导生成原始格式的比特币地址，并对毕业币地址进行规范性效验
 * @datetime: 2021/12/23 9:03
 */

public class BitCoinAddress {
    /**
     * @Author: 冷风诉离歌
     * @Description:
     * @Date: 2021/12/23 19:48
     * @Desc:该方法用于生成密钥对，并返回密钥对信息
     * @ReturnType: []
     */

    public KeyPair generateKey() {
        try {
            KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
            ECGenParameterSpec spec = new ECGenParameterSpec("secp256k1");
            generator.initialize(spec);
            return generator.generateKeyPair();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @Author: 冷风诉离歌
     * @Description:
     * @Date: 2021/12/23 9:19
     * @Desc:用于推导得到一个原始格式的地止，并将生成的地址返回
     * @ReturnType: [java.security.KeyPair]密钥对
     */

    public String newAddress(KeyPair keyPair) {
        //公钥
        ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic();

        byte[] pubKey =toUnCompressPubKey(publicKey);

        byte[] sha256 = Hash.SHA256(pubKey);
        byte[] pubhash = Hash.RipeMD160(sha256);

        //对公钥hash前面添加版本号
        byte[] version = new byte[1];
        version[0] = 0x00;

        byte[] ver_pubhash = new byte[version.length+pubhash.length];
        System.arraycopy(version,0,ver_pubhash,0,version.length);
        System.arraycopy(pubhash,0,ver_pubhash,version.length,pubhash.length);
        //对公钥hash进行双重256，取前四个字节
        Hash.SHA256(ver_pubhash);
        byte[] hash1 = Hash.SHA256(ver_pubhash);
        byte[] hash2 = Hash.SHA256(hash1);
        byte[] check = new byte[4];
        System.arraycopy(hash2,0,check,0,check.length);

        //ver_pubhash_check
        byte[] ver_pubhash_check = new byte[ver_pubhash.length+check.length];
        System.arraycopy(ver_pubhash,0,ver_pubhash_check,0,ver_pubhash.length);
        System.arraycopy(check,0,ver_pubhash_check,ver_pubhash.length,check.length);

        //对ver_pubhash_check进行base58编码
        return Base58.encode(ver_pubhash_check);

    }
    /**
     * @Author: 冷风诉离歌
     * @Description:
     * @Date: 2021/12/23 11:12
     * @Desc:该方法用于返回比特币是否符合规范 address要效验的地址
     * @ReturnType: [java.lang.String]
     */

    public boolean validateAddress(String address){
        if ("".equals(address) || address == null){
            return false;
        }

        byte[] ver_pubhash_check = Base58.decode(address);
        if (ver_pubhash_check.length < 4){
            return false;
        }
        byte[] check = new byte[4];
        System.arraycopy(ver_pubhash_check,
                ver_pubhash_check.length-4,
                check,
                0,
                check.length);

        byte[] ver_pubhash = new byte[ver_pubhash_check.length-4];
        System.arraycopy(ver_pubhash_check,
                0,
                ver_pubhash,
                0,
                ver_pubhash.length);


        //双重256，取前四个字节
        byte[] hash1 = Hash.SHA256(ver_pubhash);
        byte[] hash2 = Hash.SHA256(hash1);

        //去前四个字节
        byte[] check_sum = new byte[4];
        System.arraycopy(hash2,0,check_sum,0,check_sum.length);

        return Arrays.equals(check,check_sum);
    }
    /**
     * @Author: 冷风诉离歌
     * @Description:
     * @Date: 2021/12/23 20:34
     * @Desc:生成未压缩格式的公钥，并返回
     * @ReturnType: [java.security.interfaces.ECPublicKey]
     */

    public byte[] toUnCompressPubKey(ECPublicKey publicKey){
        ECPoint point = publicKey.getW();
        byte[] xBytes = point.getAffineX().toByteArray();
        byte[] yBytes = point.getAffineY().toByteArray();

        byte[] pubKey = new byte[1+32*2];
        pubKey[0] = 04;
        //X坐标
        if (xBytes.length == 32){
            System.arraycopy(xBytes,0,pubKey,1,xBytes.length);

        }else if (xBytes.length > 32){
            System.arraycopy(xBytes,1,pubKey,1,32);
        }
        //Y坐标
        if (yBytes.length == 32){
            System.arraycopy(yBytes,0,pubKey,33,yBytes.length);
        }else if (yBytes.length > 32){
            System.arraycopy(yBytes,1,pubKey,33,32);
        }
        return pubKey;
    }
/**
    public static void main(String[] args) {
        BitCoinAddress test = new BitCoinAddress();
        KeyPair keyPair = test.generateKey();
         String str = test.newAddress(keyPair);
         boolean result = test.validateAddress(str);
        System.out.println(result);

    }
*/
}